#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include "Xml/tinyxml.h"
#include "Xml.h"
#include "Unit.h"

Xml::NodeIndex::NodeIndex()
{
	index = 0;
	memset(name, 0, sizeof(name));
}

Xml::NodeIndex::NodeIndex( char* _name, int _index )
{
	index = _index;
	strncpy(name, _name, NAMEMAXLEN);
}

Xml::Xml(char* szFile)
{
	if ( szFile )
		m_pDoc = new class TiXmlDocument(szFile);
	else
		m_pDoc = new class TiXmlDocument();
	assert(m_pDoc);
	m_pElem = NULL;
	m_uEncoding = ENCODING_UTF8;
}

Xml::~Xml()
{
	if ( m_pDoc )
		delete m_pDoc;
}

bool Xml::InitXml(char* rootName,  bool hasDeclaration /*= false*/, uint uEnCoding)
{
	m_uEncoding = uEnCoding;
	if ( hasDeclaration )	{
		char EncodingStr[16] = "UTF-8";
		if ( m_uEncoding == ENCODING_UNKWON )
			strncpy(EncodingStr, "ASCII", 16);
		TiXmlDeclaration* pDecl = new TiXmlDeclaration("2.2",EncodingStr,"true");
		if ( pDecl )
			m_pDoc->LinkEndChild(pDecl);
	}
	TiXmlElement* pElem = NULL;
	pElem = new TiXmlElement(rootName);
	if ( !pElem )
		return false;
	if ( m_pDoc->LinkEndChild(pElem) == NULL ) {
		delete pElem;
		return false;
	}
	m_pElem = pElem;
	return true;
}

bool Xml::AddSibling(char* name)
{
	TiXmlElement* pElem = NULL;
	if ( name == NULL )
		pElem = new TiXmlElement(m_pElem->Value());
	else
		pElem = new TiXmlElement(name);
	if ( !pElem )
		return false;
	if ( m_pElem->Parent()->LinkEndChild(pElem) == NULL ){
		delete pElem;
		return false;
	}
	m_pElem = pElem;
	return true;
}

bool Xml::AddChild( char* name /*= NULL*/ )
{
	TiXmlElement* pElem = NULL;
	if ( name == NULL )
		pElem = new TiXmlElement("UnKnown");
	else
		pElem = new TiXmlElement(name);
	if ( !pElem )
		return false;
	if ( m_pElem->LinkEndChild(pElem) == NULL ){
		delete pElem;
		return false;
	}
	m_pElem = pElem;
	return true;
}

bool Xml::SaveFile( char* file /*= NULL*/ )
{
	if ( m_pDoc )
	{
		if ( file )
			return m_pDoc->SaveFile(file);
		else
			return m_pDoc->SaveFile();
	}
	return false;
}

void Xml::AddAttr(char* name, bool value)
{
	char* pStr = value? "true": "false";
	m_pElem->SetAttribute(name,pStr);
}

void Xml::AddAttr( char* name, int value)
{
	char szStr[STRINGMAXLEN]="";
	snprintf(szStr, STRINGMAXLEN, "%d", value);
	m_pElem->SetAttribute(name,szStr);
}

void Xml::AddAttr( char* name, uint value)
{
	char szStr[STRINGMAXLEN]="";
	snprintf(szStr, STRINGMAXLEN, "%u", value);
	m_pElem->SetAttribute(name,szStr);
}

void Xml::AddAttr( char* name, float value)
{
	char szStr[STRINGMAXLEN]="";
	snprintf(szStr, STRINGMAXLEN, "%f", value);
	m_pElem->SetAttribute(name,szStr);
}

void Xml::AddAttr( char* name, double value)
{
	char szStr[STRINGMAXLEN]="";
	snprintf(szStr, STRINGMAXLEN, "%0.0f", value);
	m_pElem->SetAttribute(name,szStr);
}

void Xml::AddAttr( char* name, char* value)
{
	m_pElem->SetAttribute(name,value);
}

bool Xml::SetBool( bool& value )
{
	char* pStr = value? "true": "false";
	return SetString(pStr);
}

bool Xml::SetInt( int& value )
{
	char szStr[STRINGMAXLEN]="";
	snprintf(szStr, STRINGMAXLEN, "%d", value);
	return SetString(szStr);
}

bool Xml::SetUint( uint& value )
{
	char szStr[STRINGMAXLEN]="";
	snprintf(szStr, STRINGMAXLEN, "%u", value);
	return SetString(szStr);
}

bool Xml::SetFloat( float& value )
{
	char szStr[STRINGMAXLEN]="";
	snprintf(szStr, STRINGMAXLEN, "%f", value);
	return SetString(szStr);
}

bool Xml::SetDouble( double& value )
{
	char szStr[STRINGMAXLEN]="";
	snprintf(szStr, STRINGMAXLEN, "%0.0f", value);
	return SetString(szStr);
}

bool Xml::SetString( char* value )
{
	TiXmlText* pText = new TiXmlText(value);
	if ( !pText ) return false;
	if ( m_pElem->LinkEndChild(pText) == NULL ){
		delete pText;
		return false;
	}
	return true;
}

bool Xml::LoadFile(char* szFile, uint uEnCoding)
{
	m_uEncoding = uEnCoding;
	if ( m_pDoc == NULL )
		return false;
	bool bRet = false;
	if ( szFile == NULL )
		bRet = m_pDoc->LoadFile();
	else{
		if ( uEnCoding == ENCODING_UNKWON )
			bRet = m_pDoc->LoadFile(szFile,TIXML_ENCODING_UNKNOWN);
		else
			bRet = m_pDoc->LoadFile(szFile,TIXML_ENCODING_UTF8);
	}
	if ( !bRet )
		return false;
	m_pElem = m_pDoc->RootElement();
	return true;
}

bool Xml::Root()
{
	TiXmlElement* pElem = m_pDoc->FirstChildElement();
	if ( pElem ){
		m_pElem = pElem;
		return true;
	}
	return false;
}

bool Xml::Parent()
{
	TiXmlElement* pElem = m_pElem->Parent()->ToElement();
	if ( pElem ){
		m_pElem = pElem;
		return true;
	}
	return false;
}

bool Xml::Next(char* name)
{
	TiXmlElement* pElem = NULL;
	if ( name )
		pElem = m_pElem->NextSiblingElement(name);
	else
		pElem = m_pElem->NextSiblingElement();
	if ( pElem ){
		m_pElem = pElem;
		return true;
	}
	return false;
}

bool Xml::Previous(char* name)
{
	TiXmlElement* pElem = NULL;
	TiXmlNode* node = NULL;
	if ( name )
	{
		for (	node = m_pElem->PreviousSibling( name );
				node;
				node = node->PreviousSibling( name ) )
		{
			if ( node->ToElement() ){
				pElem = node->ToElement();
				break;
			}
		}
	}
	else 
	{
		for (	node = m_pElem->PreviousSibling( );
				node;
				node = node->PreviousSibling( ) )
		{
			if ( node->ToElement() ){
				pElem = node->ToElement();
				break;
			}
		}
	}
	if ( pElem ){
		m_pElem = pElem;
		return true;
	}
	return false;
}

bool Xml::FirstChild( char* name /*= NULL*/ )
{
	TiXmlElement* pElem = NULL;
	if ( name )
		pElem = m_pElem->FirstChildElement(name);
	else
		pElem = m_pElem->FirstChildElement();
	if ( pElem ){
		m_pElem = pElem;
		return true;
	}
	return false;
}

bool Xml::LastChild( char* name /*= NULL*/ )
{
	TiXmlElement* pElem = NULL;
	TiXmlNode* node = NULL;
	if ( name )
	{
		for (	node = m_pElem->LastChild( name );
				node;
				node = node->PreviousSibling( name ) )
		{
			if ( node->ToElement() ){
				pElem = node->ToElement();
				break;
			}
		}
	}
	else 
	{
		for (	node = m_pElem->LastChild( );
				node;
				node = node->PreviousSibling( ) )
		{
			if ( node->ToElement() ){
				pElem = node->ToElement();
				break;
			}
		}
	}
	if ( pElem ){
		m_pElem = pElem;
		return true;
	}
	return false;
}

const char* Xml::Name()
{
	return m_pElem->Value();
}

bool Xml::GetBoolAttr( char* name, bool& value, bool mustExist /*= false*/, bool value1 /*= true*/ )
{
	if ( m_pElem->QueryBoolAttribute(name,&value) == 0 )
		return true;
	if ( mustExist )
		return false;
	value = value1;
	return true;
}

bool Xml::GetIntAttr( char* name, int& value, bool mustExist /*= false*/, int value1 /*= 0*/ )
{
	if ( m_pElem->QueryIntAttribute(name, &value) == 0 )
		return true;
	if ( mustExist )
		return false;
	value = value1;
	return true;
}

bool Xml::GetUintAttr( char* name, uint& value, bool mustExist /*= false*/, uint value1 /*= 0*/ )
{
	if ( m_pElem->QueryUnsignedAttribute(name, &value) == 0 )
		return true;
	if ( mustExist )
		return false;
	value = value1;
	return true;
}

bool Xml::GetFloatAttr( char* name, float& value, bool mustExist /*= false*/, float value1 /*= 0.0*/ )
{
	if ( m_pElem->QueryFloatAttribute(name, &value) == 0 )
		return true;
	if ( mustExist )
		return false;
	value = value1;
	return true;
}

bool Xml::GetDoubleAttr( char* name, double& value, bool mustExist /*= false*/, double value1 /*= 0.0*/ )
{
	if ( m_pElem->QueryDoubleAttribute(name, &value) == 0 )
		return true;
	if ( mustExist )
		return false;
	value = value1;
	return true;
}

bool Xml::GetStringAttr( char* name, char* value, int len, bool mustExist /*= false*/, char* value1 /*= ""*/ )
{
	std::string str;
	if ( m_pElem->QueryValueAttribute(name, &str) == 0 ){
		strncpy(value, str.c_str(), len);
		return true;
	}
	if ( mustExist )
		return false;
	len = (size_t)len>strlen(value1)? strlen(value1): len;
	memcpy(value, value1, len);
	return true;
}

bool Xml::GetBool( bool& value, bool mustExist /*= false*/, bool value1 /*= true*/ )
{
	const char* pStr = m_pElem->GetText();
	if ( pStr ){
		if ( 
			strcmp("false",pStr) == 0 || strcmp("FALSE",pStr) == 0 ||
			strcmp("no", pStr)   == 0 || strcmp("NO", pStr)   == 0 ||
			strcmp("0", pStr)    == 0
			)
			value = false;
		else if (
			strcmp("true",pStr)  == 0 || strcmp("TRUE",pStr)  == 0 ||
			strcmp("yes", pStr)  == 0 || strcmp("YES", pStr)  == 0 ||
			strcmp("1", pStr)    == 0
			)
			value = true;
		else
			return false;
		return true;
	}
	if ( mustExist )
		return false;
	value = value1;
	return true;
}

bool Xml::GetInt( int& value, bool mustExist /*= false*/, int value1 /*= 0*/ )
{
	const char* pStr = m_pElem->GetText();
	if ( pStr ){
		if ( sscanf(pStr, "%d", &value) != 1 )
			return false;
		return true;
	}
	if ( mustExist )
		return false;
	value = value1;
	return true;
}

bool Xml::GetUint( uint& value, bool mustExist /*= false*/, uint value1 /*= 0*/ )
{
	const char* pStr = m_pElem->GetText();
	if ( pStr ){
		if ( sscanf(pStr, "%u", &value) != 1 )
			return false;
		return true;
	}
	if ( mustExist )
		return false;
	value = value1;
	return true;
}

bool Xml::GetFloat( float& value, bool mustExist /*= false*/, float value1 /*= 0.0*/ )
{
	const char* pStr = m_pElem->GetText();
	if ( pStr ){
		if ( sscanf(pStr, "%f", &value) != 1 )
			return false;
		return true;
	}
	if ( mustExist )
		return false;
	value = value1;
	return true;
}

bool Xml::GetDouble( double& value, bool mustExist /*= false*/, double value1 /*= 0.0*/ )
{
	const char* pStr = m_pElem->GetText();
	if ( pStr ){
		if ( sscanf(pStr, "%f", &value) != 1 )
			return false;
		return true;
	}
	if ( mustExist )
		return false;
	value = value1;
	return true;
}

bool Xml::GetString( char* value, int len, bool mustExist /*= false*/, char* value1 /*= ""*/ )
{
	const char* pStr = m_pElem->GetText();
	if ( pStr ){
		if ( sscanf(pStr, "%s", &value) != 1 )
			return false;
		return true;
	}
	if ( mustExist )
		return false;
	len = (size_t)len>strlen(value1)? strlen(value1): len;
	memcpy(value, value1, len);
	return true;
}
